平台
RK3288 + Android 7.1
概述
查看系统内存使用情况, 如下图所示:
流程解读
一些字符显示
2.
packages/apps/Settings/AndroidManifest.xml [入口]
<activity android:name="Settings$MemorySettingsActivity"
android:label="@string/memory_settings_title"
android:icon="@drawable/ic_settings_memory"
android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<intent-filter android:priority="3">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.device" />
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.applications.ProcessStatsSummary" />
</activity>
相关源码
packages/apps/Settings/src/com/android/settings/applications/ProcessStatsSummary.java
packages/apps/Settings/src/com/android/settings/applications/ProcessStatsBase.java
packages/apps/Settings/src/com/android/settings/applications/ProcStatsData.java
packages/apps/Settings/src/com/android/settings/applications/ProcStatsPackageEntry.java
packages/apps/Settings/src/com/android/settings/applications/ProcessStatsUi.java
frameworks/base/services/core/java/com/android/server/am/ProcessStatsService.java
frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
frameworks/base/services/core/java/com/android/server/am/ProcessStatsService.java
public ParcelFileDescriptor getStatsOverTime(long minTime) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
long curTime;
synchronized (mAm) {
long now = SystemClock.uptimeMillis();
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
mProcessStats.mTimePeriodEndUptime = now;
mProcessStats.writeToParcel(current, now, 0);
curTime = mProcessStats.mTimePeriodEndRealtime
- mProcessStats.mTimePeriodStartRealtime;
}
mWriteLock.lock();
try {
if (curTime < minTime) {
// Need to add in older stats to reach desired time.
ArrayList<String> files = getCommittedFiles(0, false, true);
if (files != null && files.size() > 0) {
current.setDataPosition(0);
ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
current.recycle();
int i = files.size()-1;
while (i >= 0 && (stats.mTimePeriodEndRealtime
- stats.mTimePeriodStartRealtime) < minTime) {
AtomicFile file = new AtomicFile(new File(files.get(i)));
i--;
ProcessStats moreStats = new ProcessStats(false);
readLocked(moreStats, file);
if (moreStats.mReadError == null) {
stats.add(moreStats);
StringBuilder sb = new StringBuilder();
sb.append("Added stats: ");
sb.append(moreStats.mTimePeriodStartClockStr);
sb.append(", over ");
TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
- moreStats.mTimePeriodStartRealtime, sb);
Slog.i(TAG, sb.toString());
} else {
Slog.w(TAG, "Failure reading " + files.get(i+1) + "; "
+ moreStats.mReadError);
continue;
}
}
current = Parcel.obtain();
stats.writeToParcel(current, 0);
}
}
final byte[] outData = current.marshall();
current.recycle();
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
Thread thr = new Thread("ProcessStats pipe output") {
public void run() {
FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
try {
fout.write(outData);
fout.close();
} catch (IOException e) {
Slog.w(TAG, "Failure writing pipe", e);
}
}
};
thr.start();
return fds[0];
} catch (IOException e) {
Slog.w(TAG, "Failed building output pipe", e);
} finally {
mWriteLock.unlock();
}
return null;
}
private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
boolean inclCheckedIn) {
File[] files = mBaseDir.listFiles();
if (files == null || files.length <= minNum) {
return null;
}
ArrayList<String> filesArray = new ArrayList<String>(files.length);
String currentFile = mFile.getBaseFile().getPath();
if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
for (int i=0; i<files.length; i++) {
File file = files[i];
String fileStr = file.getPath();
if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
continue;
}
if (!inclCurrent && fileStr.equals(currentFile)) {
if (DEBUG) Slog.d(TAG, "Skipping: current stats");
continue;
}
filesArray.add(fileStr);
}
Collections.sort(filesArray);
return filesArray;
}
mBaseDir 是由ActivityManagerService 创建ProcessStatsService时传进来的:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
public ActivityManagerService(Context systemContext) {
//.......
// TODO: Move creation of battery stats service outside of activity manager service.
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
}
最终可以看到, ProcessStatsService会去读取data/system/procstats目录下的文件, 并解析传递数据
rk3288:/data/system/procstats # ll
total 160
-rw------- 1 system system 11276 2013-01-19 13:45 state-2013-01-19-10-44-19.bin
-rw------- 1 system system 7684 2013-01-19 16:47 state-2013-01-19-13-45-00.bin
-rw------- 1 system system 7508 2013-01-19 19:49 state-2013-01-19-16-47-00.bin
-rw------- 1 system system 7508 2013-01-19 22:50 state-2013-01-19-19-49-00.bin
-rw------- 1 system system 7912 2013-01-20 01:52 state-2013-01-19-22-50-00.bin
-rw------- 1 system system 7896 2013-01-20 04:54 state-2013-01-20-01-52-00.bin
-rw------- 1 system system 8280 2013-01-20 07:56 state-2013-01-20-04-54-00.bin
-rw------- 1 system system 7672 2013-01-20 10:58 state-2013-01-20-07-56-00.bin
-rw------- 1 system system 7656 2013-01-20 11:58 state-2013-01-20-10-58-00.bin
procstats文件的读取:
static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
int pos = 0;
final int initialAvail = stream.available();
byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
while (true) {
int amt = stream.read(data, pos, data.length-pos);
if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos
+ " of avail " + data.length);
if (amt < 0) {
if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+ " len=" + data.length);
outLen[0] = pos;
return data;
}
pos += amt;
if (pos >= data.length) {
byte[] newData = new byte[pos+16384];
if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+ newData.length);
System.arraycopy(data, 0, newData, 0, pos);
data = newData;
}
}
}
public void read(InputStream stream) {
try {
int[] len = new int[1];
byte[] raw = readFully(stream, len);
Parcel in = Parcel.obtain();
in.unmarshall(raw, 0, len[0]);
in.setDataPosition(0);
stream.close();
readFromParcel(in);
} catch (IOException e) {
mReadError = "caught exception: " + e;
}
}