Merge "Merge "Client logging changes for ProcessState and ProcessAssociation atoms" into tm-qpr-dev" into tm-qpr-dev am: b18ea46e27
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21733647 Change-Id: I9d3c334b83ca673191d8a760cc9e75cf0bdccb1a Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -73,6 +73,7 @@ import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
|
|||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class ProcessState {
|
public final class ProcessState {
|
||||||
private static final String TAG = "ProcessStats";
|
private static final String TAG = "ProcessStats";
|
||||||
@@ -1542,6 +1543,75 @@ public final class ProcessState {
|
|||||||
proto.write(fieldId, procName);
|
proto.write(fieldId, procName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dumps the duration of each state to statsEventOutput. */
|
||||||
|
public void dumpStateDurationToStatsd(
|
||||||
|
int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput) {
|
||||||
|
long topMs = 0;
|
||||||
|
long fgsMs = 0;
|
||||||
|
long boundTopMs = 0;
|
||||||
|
long boundFgsMs = 0;
|
||||||
|
long importantForegroundMs = 0;
|
||||||
|
long cachedMs = 0;
|
||||||
|
long frozenMs = 0;
|
||||||
|
long otherMs = 0;
|
||||||
|
for (int i = 0, size = mDurations.getKeyCount(); i < size; i++) {
|
||||||
|
final int key = mDurations.getKeyAt(i);
|
||||||
|
final int type = SparseMappingTable.getIdFromKey(key);
|
||||||
|
int procStateIndex = type % STATE_COUNT;
|
||||||
|
long duration = mDurations.getValue(key);
|
||||||
|
switch (procStateIndex) {
|
||||||
|
case STATE_TOP:
|
||||||
|
topMs += duration;
|
||||||
|
break;
|
||||||
|
case STATE_BOUND_TOP_OR_FGS:
|
||||||
|
boundTopMs += duration;
|
||||||
|
break;
|
||||||
|
case STATE_FGS:
|
||||||
|
fgsMs += duration;
|
||||||
|
break;
|
||||||
|
case STATE_IMPORTANT_FOREGROUND:
|
||||||
|
case STATE_IMPORTANT_BACKGROUND:
|
||||||
|
importantForegroundMs += duration;
|
||||||
|
break;
|
||||||
|
case STATE_BACKUP:
|
||||||
|
case STATE_SERVICE:
|
||||||
|
case STATE_SERVICE_RESTARTING:
|
||||||
|
case STATE_RECEIVER:
|
||||||
|
case STATE_HEAVY_WEIGHT:
|
||||||
|
case STATE_HOME:
|
||||||
|
case STATE_LAST_ACTIVITY:
|
||||||
|
case STATE_PERSISTENT:
|
||||||
|
otherMs += duration;
|
||||||
|
break;
|
||||||
|
case STATE_CACHED_ACTIVITY:
|
||||||
|
case STATE_CACHED_ACTIVITY_CLIENT:
|
||||||
|
case STATE_CACHED_EMPTY:
|
||||||
|
cachedMs += duration;
|
||||||
|
break;
|
||||||
|
// TODO (b/261910877) Add support for tracking boundFgsMs and
|
||||||
|
// frozenMs.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statsEventOutput.write(
|
||||||
|
atomTag,
|
||||||
|
getUid(),
|
||||||
|
getName(),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodStartUptime),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodEndUptime),
|
||||||
|
(int)
|
||||||
|
TimeUnit.MILLISECONDS.toSeconds(
|
||||||
|
processStats.mTimePeriodEndUptime
|
||||||
|
- processStats.mTimePeriodStartUptime),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(topMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(fgsMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(boundTopMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(boundFgsMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(importantForegroundMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(cachedMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(frozenMs),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(otherMs));
|
||||||
|
}
|
||||||
|
|
||||||
/** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
|
/** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
|
||||||
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
|
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
|
||||||
String procName, int uid, long now,
|
String procName, int uid, long now,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import android.util.proto.ProtoOutputStream;
|
|||||||
import com.android.internal.app.ProcessMap;
|
import com.android.internal.app.ProcessMap;
|
||||||
import com.android.internal.app.procstats.AssociationState.SourceKey;
|
import com.android.internal.app.procstats.AssociationState.SourceKey;
|
||||||
import com.android.internal.app.procstats.AssociationState.SourceState;
|
import com.android.internal.app.procstats.AssociationState.SourceState;
|
||||||
|
import com.android.internal.util.function.QuintConsumer;
|
||||||
|
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
@@ -56,6 +57,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -2389,6 +2392,79 @@ public final class ProcessStats implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void forEachProcess(Consumer<ProcessState> consumer) {
|
||||||
|
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
|
||||||
|
for (int ip = 0, size = procMap.size(); ip < size; ip++) {
|
||||||
|
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
|
||||||
|
for (int iu = 0, uidsSize = uids.size(); iu < uidsSize; iu++) {
|
||||||
|
final ProcessState processState = uids.valueAt(iu);
|
||||||
|
consumer.accept(processState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEachAssociation(
|
||||||
|
QuintConsumer<AssociationState, Integer, String, SourceKey, SourceState> consumer) {
|
||||||
|
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
|
||||||
|
mPackages.getMap();
|
||||||
|
for (int ip = 0, size = pkgMap.size(); ip < size; ip++) {
|
||||||
|
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
|
||||||
|
for (int iu = 0, uidsSize = uids.size(); iu < uidsSize; iu++) {
|
||||||
|
final int uid = uids.keyAt(iu);
|
||||||
|
final LongSparseArray<PackageState> versions = uids.valueAt(iu);
|
||||||
|
for (int iv = 0, versionsSize = versions.size(); iv < versionsSize; iv++) {
|
||||||
|
final PackageState state = versions.valueAt(iv);
|
||||||
|
for (int iasc = 0, ascSize = state.mAssociations.size();
|
||||||
|
iasc < ascSize;
|
||||||
|
iasc++) {
|
||||||
|
final String serviceName = state.mAssociations.keyAt(iasc);
|
||||||
|
final AssociationState asc = state.mAssociations.valueAt(iasc);
|
||||||
|
for (int is = 0, sourcesSize = asc.mSources.size();
|
||||||
|
is < sourcesSize;
|
||||||
|
is++) {
|
||||||
|
final SourceState src = asc.mSources.valueAt(is);
|
||||||
|
final SourceKey key = asc.mSources.keyAt(is);
|
||||||
|
consumer.accept(asc, uid, serviceName, key, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dumps the stats of all processes to statsEventOutput. */
|
||||||
|
public void dumpProcessState(int atomTag, StatsEventOutput statsEventOutput) {
|
||||||
|
forEachProcess(
|
||||||
|
(processState) -> {
|
||||||
|
if (processState.isMultiPackage()
|
||||||
|
&& processState.getCommonProcess() != processState) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processState.dumpStateDurationToStatsd(atomTag, this, statsEventOutput);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dumps all process association data to statsEventOutput. */
|
||||||
|
public void dumpProcessAssociation(int atomTag, StatsEventOutput statsEventOutput) {
|
||||||
|
forEachAssociation(
|
||||||
|
(asc, serviceUid, serviceName, key, src) -> {
|
||||||
|
statsEventOutput.write(
|
||||||
|
atomTag,
|
||||||
|
key.mUid,
|
||||||
|
key.mProcess,
|
||||||
|
serviceUid,
|
||||||
|
serviceName,
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(mTimePeriodStartUptime),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(mTimePeriodEndUptime),
|
||||||
|
(int)
|
||||||
|
TimeUnit.MILLISECONDS.toSeconds(
|
||||||
|
mTimePeriodEndUptime - mTimePeriodStartUptime),
|
||||||
|
(int) TimeUnit.MILLISECONDS.toSeconds(src.mDuration),
|
||||||
|
src.mActiveCount,
|
||||||
|
asc.getProcessName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void dumpProtoPreamble(ProtoOutputStream proto) {
|
private void dumpProtoPreamble(ProtoOutputStream proto) {
|
||||||
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
|
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
|
||||||
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
|
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.app.procstats;
|
||||||
|
|
||||||
|
import android.util.StatsEvent;
|
||||||
|
|
||||||
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple wrapper of FrameworkStatsLog.buildStatsEvent. This allows unit tests to mock out the
|
||||||
|
* dependency.
|
||||||
|
*/
|
||||||
|
public class StatsEventOutput {
|
||||||
|
|
||||||
|
List<StatsEvent> mOutput;
|
||||||
|
|
||||||
|
public StatsEventOutput(List<StatsEvent> output) {
|
||||||
|
mOutput = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Writes the data to the output. */
|
||||||
|
public void write(
|
||||||
|
int atomTag,
|
||||||
|
int uid,
|
||||||
|
String processName,
|
||||||
|
int measurementStartUptimeSecs,
|
||||||
|
int measurementEndUptimeSecs,
|
||||||
|
int measurementDurationUptimeSecs,
|
||||||
|
int topSeconds,
|
||||||
|
int fgsSeconds,
|
||||||
|
int boundTopSeconds,
|
||||||
|
int boundFgsSeconds,
|
||||||
|
int importantForegroundSeconds,
|
||||||
|
int cachedSeconds,
|
||||||
|
int frozenSeconds,
|
||||||
|
int otherSeconds) {
|
||||||
|
mOutput.add(
|
||||||
|
FrameworkStatsLog.buildStatsEvent(
|
||||||
|
atomTag,
|
||||||
|
uid,
|
||||||
|
processName,
|
||||||
|
measurementStartUptimeSecs,
|
||||||
|
measurementEndUptimeSecs,
|
||||||
|
measurementDurationUptimeSecs,
|
||||||
|
topSeconds,
|
||||||
|
fgsSeconds,
|
||||||
|
boundTopSeconds,
|
||||||
|
boundFgsSeconds,
|
||||||
|
importantForegroundSeconds,
|
||||||
|
cachedSeconds,
|
||||||
|
frozenSeconds,
|
||||||
|
otherSeconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Writes the data to the output. */
|
||||||
|
public void write(
|
||||||
|
int atomTag,
|
||||||
|
int clientUid,
|
||||||
|
String processName,
|
||||||
|
int serviceUid,
|
||||||
|
String serviceName,
|
||||||
|
int measurementStartUptimeSecs,
|
||||||
|
int measurementEndUptimeSecs,
|
||||||
|
int measurementDurationUptimeSecs,
|
||||||
|
int activeDurationUptimeSecs,
|
||||||
|
int activeCount,
|
||||||
|
String serviceProcessName) {
|
||||||
|
mOutput.add(
|
||||||
|
FrameworkStatsLog.buildStatsEvent(
|
||||||
|
atomTag,
|
||||||
|
clientUid,
|
||||||
|
processName,
|
||||||
|
serviceUid,
|
||||||
|
serviceName,
|
||||||
|
measurementStartUptimeSecs,
|
||||||
|
measurementEndUptimeSecs,
|
||||||
|
measurementDurationUptimeSecs,
|
||||||
|
activeDurationUptimeSecs,
|
||||||
|
activeCount,
|
||||||
|
serviceProcessName));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.internal.app.procstats;
|
||||||
|
|
||||||
|
import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/** Provides test cases for ProcessStats. */
|
||||||
|
public class ProcessStatsTest extends TestCase {
|
||||||
|
|
||||||
|
private static final String APP_1_PACKAGE_NAME = "com.android.testapp";
|
||||||
|
private static final int APP_1_UID = 5001;
|
||||||
|
private static final long APP_1_VERSION = 10;
|
||||||
|
private static final String APP_1_PROCESS_NAME = "com.android.testapp.p";
|
||||||
|
private static final String APP_1_SERVICE_NAME = "com.android.testapp.service";
|
||||||
|
|
||||||
|
private static final String APP_2_PACKAGE_NAME = "com.android.testapp2";
|
||||||
|
private static final int APP_2_UID = 5002;
|
||||||
|
private static final long APP_2_VERSION = 30;
|
||||||
|
private static final String APP_2_PROCESS_NAME = "com.android.testapp2.p";
|
||||||
|
|
||||||
|
private static final long NOW_MS = 123000;
|
||||||
|
private static final int DURATION_SECS = 6;
|
||||||
|
|
||||||
|
@Mock StatsEventOutput mStatsEventOutput;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testDumpProcessState() throws Exception {
|
||||||
|
ProcessStats processStats = new ProcessStats();
|
||||||
|
processStats.getProcessStateLocked(
|
||||||
|
APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
|
||||||
|
processStats.getProcessStateLocked(
|
||||||
|
APP_2_PACKAGE_NAME, APP_2_UID, APP_2_VERSION, APP_2_PROCESS_NAME);
|
||||||
|
processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
|
||||||
|
verify(mStatsEventOutput)
|
||||||
|
.write(
|
||||||
|
eq(FrameworkStatsLog.PROCESS_STATE),
|
||||||
|
eq(APP_1_UID),
|
||||||
|
eq(APP_1_PROCESS_NAME),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0));
|
||||||
|
verify(mStatsEventOutput)
|
||||||
|
.write(
|
||||||
|
eq(FrameworkStatsLog.PROCESS_STATE),
|
||||||
|
eq(APP_2_UID),
|
||||||
|
eq(APP_2_PROCESS_NAME),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testNonZeroProcessStateDuration() throws Exception {
|
||||||
|
ProcessStats processStats = new ProcessStats();
|
||||||
|
ProcessState processState =
|
||||||
|
processStats.getProcessStateLocked(
|
||||||
|
APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
|
||||||
|
processState.setCombinedState(STATE_TOP, NOW_MS);
|
||||||
|
processState.commitStateTime(NOW_MS + TimeUnit.SECONDS.toMillis(DURATION_SECS));
|
||||||
|
processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
|
||||||
|
verify(mStatsEventOutput)
|
||||||
|
.write(
|
||||||
|
eq(FrameworkStatsLog.PROCESS_STATE),
|
||||||
|
eq(APP_1_UID),
|
||||||
|
eq(APP_1_PROCESS_NAME),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
eq(0),
|
||||||
|
eq(DURATION_SECS),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testDumpProcessAssociation() throws Exception {
|
||||||
|
ProcessStats processStats = new ProcessStats();
|
||||||
|
AssociationState associationState =
|
||||||
|
processStats.getAssociationStateLocked(
|
||||||
|
APP_1_PACKAGE_NAME,
|
||||||
|
APP_1_UID,
|
||||||
|
APP_1_VERSION,
|
||||||
|
APP_1_PROCESS_NAME,
|
||||||
|
APP_1_SERVICE_NAME);
|
||||||
|
AssociationState.SourceState sourceState =
|
||||||
|
associationState.startSource(APP_2_UID, APP_2_PROCESS_NAME, APP_2_PACKAGE_NAME);
|
||||||
|
sourceState.stop();
|
||||||
|
processStats.dumpProcessAssociation(
|
||||||
|
FrameworkStatsLog.PROCESS_ASSOCIATION, mStatsEventOutput);
|
||||||
|
verify(mStatsEventOutput)
|
||||||
|
.write(
|
||||||
|
eq(FrameworkStatsLog.PROCESS_ASSOCIATION),
|
||||||
|
eq(APP_2_UID),
|
||||||
|
eq(APP_2_PROCESS_NAME),
|
||||||
|
eq(APP_1_UID),
|
||||||
|
eq(APP_1_SERVICE_NAME),
|
||||||
|
anyInt(),
|
||||||
|
anyInt(),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(0),
|
||||||
|
eq(APP_1_PROCESS_NAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,6 +169,7 @@ import android.view.Display;
|
|||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.app.procstats.IProcessStats;
|
import com.android.internal.app.procstats.IProcessStats;
|
||||||
import com.android.internal.app.procstats.ProcessStats;
|
import com.android.internal.app.procstats.ProcessStats;
|
||||||
|
import com.android.internal.app.procstats.StatsEventOutput;
|
||||||
import com.android.internal.os.BackgroundThread;
|
import com.android.internal.os.BackgroundThread;
|
||||||
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
|
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
|
||||||
import com.android.internal.os.KernelAllocationStats;
|
import com.android.internal.os.KernelAllocationStats;
|
||||||
@@ -612,12 +613,19 @@ public class StatsPullAtomService extends SystemService {
|
|||||||
}
|
}
|
||||||
case FrameworkStatsLog.PROC_STATS:
|
case FrameworkStatsLog.PROC_STATS:
|
||||||
synchronized (mProcStatsLock) {
|
synchronized (mProcStatsLock) {
|
||||||
return pullProcStatsLocked(ProcessStats.REPORT_ALL, atomTag, data);
|
return pullProcStatsLocked(atomTag, data);
|
||||||
}
|
}
|
||||||
case FrameworkStatsLog.PROC_STATS_PKG_PROC:
|
case FrameworkStatsLog.PROC_STATS_PKG_PROC:
|
||||||
synchronized (mProcStatsLock) {
|
synchronized (mProcStatsLock) {
|
||||||
return pullProcStatsLocked(ProcessStats.REPORT_PKG_PROC_STATS, atomTag,
|
return pullProcStatsLocked(atomTag, data);
|
||||||
data);
|
}
|
||||||
|
case FrameworkStatsLog.PROCESS_STATE:
|
||||||
|
synchronized (mProcStatsLock) {
|
||||||
|
return pullProcessStateLocked(atomTag, data);
|
||||||
|
}
|
||||||
|
case FrameworkStatsLog.PROCESS_ASSOCIATION:
|
||||||
|
synchronized (mProcStatsLock) {
|
||||||
|
return pullProcessAssociationLocked(atomTag, data);
|
||||||
}
|
}
|
||||||
case FrameworkStatsLog.DISK_IO:
|
case FrameworkStatsLog.DISK_IO:
|
||||||
synchronized (mDiskIoLock) {
|
synchronized (mDiskIoLock) {
|
||||||
@@ -890,6 +898,8 @@ public class StatsPullAtomService extends SystemService {
|
|||||||
registerNumFacesEnrolled();
|
registerNumFacesEnrolled();
|
||||||
registerProcStats();
|
registerProcStats();
|
||||||
registerProcStatsPkgProc();
|
registerProcStatsPkgProc();
|
||||||
|
registerProcessState();
|
||||||
|
registerProcessAssociation();
|
||||||
registerDiskIO();
|
registerDiskIO();
|
||||||
registerPowerProfile();
|
registerPowerProfile();
|
||||||
registerProcessCpuTime();
|
registerProcessCpuTime();
|
||||||
@@ -2870,59 +2880,138 @@ public class StatsPullAtomService extends SystemService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int pullProcStatsLocked(int section, int atomTag, List<StatsEvent> pulledData) {
|
private void registerProcessState() {
|
||||||
|
int tagId = FrameworkStatsLog.PROCESS_STATE;
|
||||||
|
mStatsManager.setPullAtomCallback(
|
||||||
|
tagId,
|
||||||
|
null, // use default PullAtomMetadata values
|
||||||
|
DIRECT_EXECUTOR,
|
||||||
|
mStatsCallbackImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerProcessAssociation() {
|
||||||
|
int tagId = FrameworkStatsLog.PROCESS_ASSOCIATION;
|
||||||
|
mStatsManager.setPullAtomCallback(
|
||||||
|
tagId,
|
||||||
|
null, // use default PullAtomMetadata values
|
||||||
|
DIRECT_EXECUTOR,
|
||||||
|
mStatsCallbackImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mProcStatsLock")
|
||||||
|
private ProcessStats getStatsFromProcessStatsService(int atomTag) {
|
||||||
IProcessStats processStatsService = getIProcessStatsService();
|
IProcessStats processStatsService = getIProcessStatsService();
|
||||||
if (processStatsService == null) {
|
if (processStatsService == null) {
|
||||||
return StatsManager.PULL_SKIP;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
// force procstats to flush & combine old files into one store
|
// force procstats to flush & combine old files into one store
|
||||||
long lastHighWaterMark = readProcStatsHighWaterMark(section);
|
long lastHighWaterMark = readProcStatsHighWaterMark(atomTag);
|
||||||
|
|
||||||
ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
|
|
||||||
for (int i = 0; i < protoStreams.length; i++) {
|
|
||||||
protoStreams[i] = new ProtoOutputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessStats procStats = new ProcessStats(false);
|
ProcessStats procStats = new ProcessStats(false);
|
||||||
// Force processStatsService to aggregate all in-storage and in-memory data.
|
// Force processStatsService to aggregate all in-storage and in-memory data.
|
||||||
long highWaterMark = processStatsService.getCommittedStatsMerged(
|
long highWaterMark =
|
||||||
lastHighWaterMark, section, true, null, procStats);
|
processStatsService.getCommittedStatsMerged(
|
||||||
procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
|
lastHighWaterMark,
|
||||||
|
ProcessStats.REPORT_ALL, // ignored since committedStats below is null.
|
||||||
for (int i = 0; i < protoStreams.length; i++) {
|
true,
|
||||||
byte[] bytes = protoStreams[i].getBytes(); // cache the value
|
null, // committedStats
|
||||||
if (bytes.length > 0) {
|
procStats);
|
||||||
pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, bytes,
|
new File(
|
||||||
// This is a shard ID, and is specified in the metric definition to be
|
mBaseDir.getAbsolutePath()
|
||||||
// a dimension. This will result in statsd using RANDOM_ONE_SAMPLE to
|
+ "/"
|
||||||
// keep all the shards, as it thinks each shard is a different dimension
|
+ highWaterMarkFilePrefix(atomTag)
|
||||||
// of data.
|
+ "_"
|
||||||
i));
|
+ lastHighWaterMark)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
|
|
||||||
.delete();
|
.delete();
|
||||||
new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
|
new File(
|
||||||
|
mBaseDir.getAbsolutePath()
|
||||||
|
+ "/"
|
||||||
|
+ highWaterMarkFilePrefix(atomTag)
|
||||||
|
+ "_"
|
||||||
|
+ highWaterMark)
|
||||||
.createNewFile();
|
.createNewFile();
|
||||||
|
return procStats;
|
||||||
} catch (RemoteException | IOException e) {
|
} catch (RemoteException | IOException e) {
|
||||||
Slog.e(TAG, "Getting procstats failed: ", e);
|
Slog.e(TAG, "Getting procstats failed: ", e);
|
||||||
return StatsManager.PULL_SKIP;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mProcStatsLock")
|
||||||
|
private int pullProcStatsLocked(int atomTag, List<StatsEvent> pulledData) {
|
||||||
|
ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
|
||||||
|
if (procStats == null) {
|
||||||
|
return StatsManager.PULL_SKIP;
|
||||||
|
}
|
||||||
|
ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
|
||||||
|
for (int i = 0; i < protoStreams.length; i++) {
|
||||||
|
protoStreams[i] = new ProtoOutputStream();
|
||||||
|
}
|
||||||
|
procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
|
||||||
|
for (int i = 0; i < protoStreams.length; i++) {
|
||||||
|
byte[] bytes = protoStreams[i].getBytes(); // cache the value
|
||||||
|
if (bytes.length > 0) {
|
||||||
|
pulledData.add(
|
||||||
|
FrameworkStatsLog.buildStatsEvent(
|
||||||
|
atomTag,
|
||||||
|
bytes,
|
||||||
|
// This is a shard ID, and is specified in the metric definition to
|
||||||
|
// be
|
||||||
|
// a dimension. This will result in statsd using RANDOM_ONE_SAMPLE
|
||||||
|
// to
|
||||||
|
// keep all the shards, as it thinks each shard is a different
|
||||||
|
// dimension
|
||||||
|
// of data.
|
||||||
|
i));
|
||||||
|
}
|
||||||
|
}
|
||||||
return StatsManager.PULL_SUCCESS;
|
return StatsManager.PULL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mProcStatsLock")
|
||||||
|
private int pullProcessStateLocked(int atomTag, List<StatsEvent> pulledData) {
|
||||||
|
ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
|
||||||
|
if (procStats == null) {
|
||||||
|
return StatsManager.PULL_SKIP;
|
||||||
|
}
|
||||||
|
procStats.dumpProcessState(atomTag, new StatsEventOutput(pulledData));
|
||||||
|
return StatsManager.PULL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mProcStatsLock")
|
||||||
|
private int pullProcessAssociationLocked(int atomTag, List<StatsEvent> pulledData) {
|
||||||
|
ProcessStats procStats = getStatsFromProcessStatsService(atomTag);
|
||||||
|
if (procStats == null) {
|
||||||
|
return StatsManager.PULL_SKIP;
|
||||||
|
}
|
||||||
|
procStats.dumpProcessAssociation(atomTag, new StatsEventOutput(pulledData));
|
||||||
|
return StatsManager.PULL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String highWaterMarkFilePrefix(int atomTag) {
|
||||||
|
// For backward compatibility, use the legacy ProcessStats enum value as the prefix for
|
||||||
|
// PROC_STATS and PROC_STATS_PKG_PROC.
|
||||||
|
if (atomTag == FrameworkStatsLog.PROC_STATS) {
|
||||||
|
return String.valueOf(ProcessStats.REPORT_ALL);
|
||||||
|
}
|
||||||
|
if (atomTag == FrameworkStatsLog.PROC_STATS_PKG_PROC) {
|
||||||
|
return String.valueOf(ProcessStats.REPORT_PKG_PROC_STATS);
|
||||||
|
}
|
||||||
|
return "atom-" + atomTag;
|
||||||
|
}
|
||||||
|
|
||||||
// read high watermark for section
|
// read high watermark for section
|
||||||
private long readProcStatsHighWaterMark(int section) {
|
private long readProcStatsHighWaterMark(int atomTag) {
|
||||||
try {
|
try {
|
||||||
File[] files = mBaseDir.listFiles((d, name) -> {
|
File[] files =
|
||||||
return name.toLowerCase().startsWith(String.valueOf(section) + '_');
|
mBaseDir.listFiles(
|
||||||
});
|
(d, name) -> {
|
||||||
|
return name.toLowerCase()
|
||||||
|
.startsWith(highWaterMarkFilePrefix(atomTag) + '_');
|
||||||
|
});
|
||||||
if (files == null || files.length == 0) {
|
if (files == null || files.length == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user