106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski/* 206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 306af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * 406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * you may not use this file except in compliance with the License. 606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * You may obtain a copy of the License at 706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * 806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 906af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * 1006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Unless required by applicable law or agreed to in writing, software 1106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 1206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1306af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * See the License for the specific language governing permissions and 1406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * limitations under the License. 1506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski */ 1606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskipackage com.android.internal.os; 1706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 1806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport android.annotation.Nullable; 1972478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinskiimport android.os.SystemClock; 2006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport android.text.TextUtils; 2106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport android.util.Slog; 2206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport android.util.SparseLongArray; 2372478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinskiimport android.util.TimeUtils; 2406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 2506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport java.io.BufferedReader; 2606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport java.io.FileReader; 27b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinskiimport java.io.FileWriter; 2806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskiimport java.io.IOException; 2906af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 3006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski/** 3106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Reads /proc/uid_cputime/show_uid_stat which has the line format: 3206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * 33a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski * uid: user_time_micro_seconds system_time_micro_seconds power_in_milli-amp-micro_seconds 3406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * 3506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * This provides the time a UID's processes spent executing in user-space and kernel-space. 3606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * The file contains a monotonically increasing count of time for a single boot. This class 3706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * maintains the previous results of a call to {@link #readDelta} in order to provide a proper 3806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * delta. 3906af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski */ 4006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinskipublic class KernelUidCpuTimeReader { 4106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski private static final String TAG = "KernelUidCpuTimeReader"; 4206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski private static final String sProcFile = "/proc/uid_cputime/show_uid_stat"; 43b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range"; 4406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 4506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski /** 4606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Callback interface for processing each line of the proc file. 4706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski */ 4806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski public interface Callback { 49a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski /** 50a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski * @param uid UID of the app 51a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski * @param userTimeUs time spent executing in user space in microseconds 52a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski * @param systemTimeUs time spent executing in kernel space in microseconds 53a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski */ 54d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs); 5506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 5606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 5706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski private SparseLongArray mLastUserTimeUs = new SparseLongArray(); 5806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski private SparseLongArray mLastSystemTimeUs = new SparseLongArray(); 597b3c7529c73581f360cdcd0243e8c68e1cdedb43Adam Lesinski private long mLastTimeReadUs = 0; 6006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 6106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski /** 6206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * Reads the proc file, calling into the callback with a delta of time for each UID. 6306af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * @param callback The callback to invoke for each line of the proc file. If null, 6406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * the data is consumed and subsequent calls to readDelta will provide 6506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski * a fresh delta. 6606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski */ 6706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski public void readDelta(@Nullable Callback callback) { 687b3c7529c73581f360cdcd0243e8c68e1cdedb43Adam Lesinski long nowUs = SystemClock.elapsedRealtime() * 1000; 6906af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { 7006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); 7106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski String line; 7206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski while ((line = reader.readLine()) != null) { 7306af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski splitter.setString(line); 7406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski final String uidStr = splitter.next(); 7506af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski final int uid = Integer.parseInt(uidStr.substring(0, uidStr.length() - 1), 10); 7606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski final long userTimeUs = Long.parseLong(splitter.next(), 10); 7706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski final long systemTimeUs = Long.parseLong(splitter.next(), 10); 7806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski 79e7f4f0297fe77fd76f944b9a3134534962833262Adam Lesinski // Only report if there is a callback and if this is not the first read. 80e7f4f0297fe77fd76f944b9a3134534962833262Adam Lesinski if (callback != null && mLastTimeReadUs != 0) { 81b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski long userTimeDeltaUs = userTimeUs; 82b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski long systemTimeDeltaUs = systemTimeUs; 8306af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski int index = mLastUserTimeUs.indexOfKey(uid); 84b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski if (index >= 0) { 85b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski userTimeDeltaUs -= mLastUserTimeUs.valueAt(index); 86b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski systemTimeDeltaUs -= mLastSystemTimeUs.valueAt(index); 87b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski 887b3c7529c73581f360cdcd0243e8c68e1cdedb43Adam Lesinski final long timeDiffUs = nowUs - mLastTimeReadUs; 89d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski if (userTimeDeltaUs < 0 || systemTimeDeltaUs < 0) { 90a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski StringBuilder sb = new StringBuilder("Malformed cpu data for UID="); 91a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski sb.append(uid).append("!\n"); 9272478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski sb.append("Time between reads: "); 937b3c7529c73581f360cdcd0243e8c68e1cdedb43Adam Lesinski TimeUtils.formatDuration(timeDiffUs / 1000, sb); 94a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski sb.append("\n"); 9572478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski sb.append("Previous times: u="); 9672478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(mLastUserTimeUs.valueAt(index) / 1000, sb); 97a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski sb.append(" s="); 9872478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(mLastSystemTimeUs.valueAt(index) / 1000, sb); 99a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski 100d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski sb.append("\nCurrent times: u="); 10172478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(userTimeUs / 1000, sb); 102a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski sb.append(" s="); 10372478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(systemTimeUs / 1000, sb); 104d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski sb.append("\nDelta: u="); 10572478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(userTimeDeltaUs / 1000, sb); 106a7a4cccf7d90324a049fbfd271d25cad51633922Adam Lesinski sb.append(" s="); 10772478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb); 108196473955f9dfeb29b30757ad49df3ed68d6f65eAdam Lesinski Slog.e(TAG, sb.toString()); 10972478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski 11072478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski userTimeDeltaUs = 0; 11172478f053f403e29223dba6cc7be9e5bf115f670Adam Lesinski systemTimeDeltaUs = 0; 112b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } 113b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } 114b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski 115d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski if (userTimeDeltaUs != 0 || systemTimeDeltaUs != 0) { 116d4abd1eeb01187fa2ef78b64ae4f493a7bb3563fAdam Lesinski callback.onUidCpuTime(uid, userTimeDeltaUs, systemTimeDeltaUs); 11706af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 11806af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 11906af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski mLastUserTimeUs.put(uid, userTimeUs); 12006af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski mLastSystemTimeUs.put(uid, systemTimeUs); 12106af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 12206af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } catch (IOException e) { 1238057133d49ab3243de54333012ce5ee8fece5381Adam Lesinski Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage()); 12406af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 1257b3c7529c73581f360cdcd0243e8c68e1cdedb43Adam Lesinski mLastTimeReadUs = nowUs; 12606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski } 127b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski 128b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski /** 129b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski * Removes the UID from the kernel module and from internal accounting data. 130b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski * @param uid The UID to remove. 131b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski */ 132b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski public void removeUid(int uid) { 133b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski int index = mLastUserTimeUs.indexOfKey(uid); 134b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski if (index >= 0) { 135b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski mLastUserTimeUs.removeAt(index); 136b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski mLastSystemTimeUs.removeAt(index); 137b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } 138b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski 139b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) { 140b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski writer.write(Integer.toString(uid) + "-" + Integer.toString(uid)); 141b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski writer.flush(); 142b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } catch (IOException e) { 143b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski Slog.e(TAG, "failed to remove uid from uid_cputime module", e); 144b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } 145b83ffee5a40bf00e156152ad85bf8cf6bb96e2f1Adam Lesinski } 14606af1fac166a83507450b6bbb1f98a8dde68d92eAdam Lesinski} 147