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

Commit b6f158c4 authored by Varun Shah's avatar Varun Shah Committed by Android (Google) Code Review
Browse files

Merge "Update standby bucket for uninteracted foreground services." into qt-dev

parents 54429c1b 334d6764
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -543,7 +543,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
    private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
    final OomAdjuster mOomAdjuster;
    OomAdjuster mOomAdjuster;
    final LowMemDetector mLowMemDetector;
    final LowMemDetector mLowMemDetector;
    /** All system services */
    /** All system services */
@@ -1483,7 +1483,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    final ServiceThread mProcStartHandlerThread;
    final ServiceThread mProcStartHandlerThread;
    final Handler mProcStartHandler;
    final Handler mProcStartHandler;
    final ActivityManagerConstants mConstants;
    ActivityManagerConstants mConstants;
    // Encapsulates the global setting "hidden_api_blacklist_exemptions"
    // Encapsulates the global setting "hidden_api_blacklist_exemptions"
    final HiddenApiSettings mHiddenApiBlacklist;
    final HiddenApiSettings mHiddenApiBlacklist;
+13 −0
Original line number Original line Diff line number Diff line
@@ -75,6 +75,7 @@ import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoOutputStream;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -1897,6 +1898,10 @@ public final class OomAdjuster {
            // For apps that sit around for a long time in the interactive state, we need
            // For apps that sit around for a long time in the interactive state, we need
            // to report this at least once a day so they don't go idle.
            // to report this at least once a day so they don't go idle.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
                > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
            // For foreground services that sit around for a long time but are not interacted with.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        }
        }


        if (changes != 0) {
        if (changes != 0) {
@@ -1917,6 +1922,14 @@ public final class OomAdjuster {
        return success;
        return success;
    }
    }


    // ONLY used for unit testing in OomAdjusterTests.java
    @VisibleForTesting
    void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) {
        synchronized (mService) {
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        }
    }

    @GuardedBy("mService")
    @GuardedBy("mService")
    private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
    private void maybeUpdateUsageStatsLocked(ProcessRecord app, long nowElapsed) {
        if (DEBUG_USAGE_STATS) {
        if (DEBUG_USAGE_STATS) {
+255 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.am;

import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;

import android.app.ActivityManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;

import com.android.server.LocalServices;
import com.android.server.wm.ActivityTaskManagerService;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Test class for {@link OomAdjuster}.
 *
 * Build/Install/Run:
 *  atest FrameworksServicesTests:OomAdjusterTests
 */
public class OomAdjusterTests {
    private static Context sContext;
    private static ActivityManagerService sService;

    private ProcessRecord mProcessRecord;

    private static final long ZERO = 0L;
    private static final long USAGE_STATS_INTERACTION = 2 * 60 * 60 * 1000L;
    private static final long SERVICE_USAGE_INTERACTION = 30 * 60 * 1000;

    @BeforeClass
    public static void setUpOnce() {
        sContext = getInstrumentation().getTargetContext();

        // We need to run with dexmaker share class loader to make use of
        // ActivityTaskManagerService from wm package.
        runWithDexmakerShareClassLoader(() -> {
            sService = mock(ActivityManagerService.class);
            sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
            sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
            sService.mAtmInternal = sService.mActivityTaskManager.getAtmInternal();

            sService.mConstants = new ActivityManagerConstants(sContext, sService,
                    sContext.getMainThreadHandler());
            sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null);
            LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
            LocalServices.addService(UsageStatsManagerInternal.class,
                    mock(UsageStatsManagerInternal.class));
            sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
        });
    }

    @Before
    public void setUpProcess() {
        // Need to run with dexmaker share class loader to mock package private class.
        runWithDexmakerShareClassLoader(() -> {
            mProcessRecord = spy(new ProcessRecord(sService, sContext.getApplicationInfo(),
                    "name", 12345));
        });

        // Ensure certain services and constants are defined properly
        assertNotNull(sService.mUsageStatsService);
        assertEquals(USAGE_STATS_INTERACTION, sService.mConstants.USAGE_STATS_INTERACTION_INTERVAL);
        assertEquals(SERVICE_USAGE_INTERACTION, sService.mConstants.SERVICE_USAGE_INTERACTION_TIME);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStatePersistentUI() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateTop() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateTop_PreviousInteraction() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
        mProcessRecord.reportedInteraction = true;
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateTop_PastUsageInterval() {
        final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_TOP);
        mProcessRecord.reportedInteraction = true;
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateBoundTop() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_TOP);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateFGS() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(elapsedTime, false, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateFGS_ShortInteraction() {
        final long elapsedTime = ZERO;
        final long fgInteractionTime = 1000L;
        mProcessRecord.setFgInteractionTime(fgInteractionTime);
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(fgInteractionTime, false, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateFGS_LongInteraction() {
        final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
        final long fgInteractionTime = 1000L;
        mProcessRecord.setFgInteractionTime(fgInteractionTime);
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(fgInteractionTime, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateFGS_PreviousLongInteraction() {
        final long elapsedTime = 2 * SERVICE_USAGE_INTERACTION;
        final long fgInteractionTime = 1000L;
        mProcessRecord.setFgInteractionTime(fgInteractionTime);
        mProcessRecord.reportedInteraction = true;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(fgInteractionTime, true, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateFGSLocation() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(elapsedTime, false, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateBFGS() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateImportantFG() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateImportantFG_PreviousInteraction() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
        mProcessRecord.reportedInteraction = true;
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateImportantFG_PastUsageInterval() {
        final long elapsedTime = 3 * USAGE_STATS_INTERACTION;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
        mProcessRecord.reportedInteraction = true;
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, true, elapsedTime);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateImportantBG() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, false, ZERO);
    }

    @Test
    public void testMaybeUpdateUsageStats_ProcStateService() {
        final long elapsedTime = ZERO;
        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_SERVICE);
        sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);

        assertProcessRecordState(ZERO, false, ZERO);
    }

    private void assertProcessRecordState(long fgInteractionTime, boolean reportedInteraction,
            long interactionEventTime) {
        assertEquals("Foreground interaction time was not updated correctly.",
                fgInteractionTime, mProcessRecord.getFgInteractionTime());
        assertEquals("Interaction was not updated correctly.",
                reportedInteraction, mProcessRecord.reportedInteraction);
        assertEquals("Interaction event time was not updated correctly.",
                interactionEventTime, mProcessRecord.getInteractionEventTime());
    }
}