Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ada70107 authored by Yu-Ting Tseng's avatar Yu-Ting Tseng Committed by Automerger Merge Worker
Browse files

Merge "Merge "Client logging changes for ProcessState and ProcessAssociation...

Merge "Merge "Client logging changes for ProcessState and ProcessAssociation atoms" into tm-qpr-dev" into tm-qpr-dev am: b18ea46e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21733647



Change-Id: I9d3c334b83ca673191d8a760cc9e75cf0bdccb1a
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 85d4817e b18ea46e
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;

import java.io.PrintWriter;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;

public final class ProcessState {
    private static final String TAG = "ProcessStats";
@@ -1542,6 +1543,75 @@ public final class ProcessState {
        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. */
    public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
            String procName, int uid, long now,
+76 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.AssociationState.SourceKey;
import com.android.internal.app.procstats.AssociationState.SourceState;
import com.android.internal.util.function.QuintConsumer;

import dalvik.system.VMRuntime;

@@ -56,6 +57,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.regex.Matcher;
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) {
        proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
        proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
+98 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}
+159 −0
Original line number Diff line number Diff line
/*
 * 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));
    }
}
+125 −36

File changed.

Preview size limit exceeded, changes collapsed.