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

Commit 183f8d21 authored by Zim's avatar Zim
Browse files

Skip computing proc states during app initialization [take #2]

Now that app initialization covers class loading, there can be
hundreds of milliseconds delay before a top app activity gets
scheduled to start. During this delay, computing proc states
overrides the top app special case set at attachApplication to
boost the sched group.

This is fixed with the following changes:
1. Skip computing proc states when the application hasn't finished
attach application
2. Trigger a proc state update immediately after scheduling
bindApplication. This ensures that the special cased proc state is
applied as soon as possible

The previous attempt had a bug where setting the verified
and raw oom_adj to foreground_app broke subseqeunt computations of
the oom_adj and proc states after finish attach application to compute
wrong scores and broke a bunch of tests. The curAdj is the value
that gets sent to the kernel when we apply oomAdj, and we set
that to foreground_app in the pending finish attach phase.

All those tests now pass with the new fix

Test: atest MockingOomAdjusterTests
Test: atest android.app.cts.ActivityManagerProcessStateTest
Test: atest android.app.cts.ActivityManagerFgsBgStartTest
Test: atest android.app.cts.ActivityManagerTest
Test: atest android.app.cts.ServiceTest
Test: atest android.permission.cts.FileSystemPermissionTest
Test: atest android.permission.cts.OneTimePermissionTest
Bug: 253908737
Bug: 272062082
Change-Id: I73885b0f424831a1417586701d5f804a64af9a29
parent d26c87b3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1357,7 +1357,7 @@ final class ActivityManagerConstants extends ContentObserver {
        updateForegroundServiceStartsLoggingEnabled();
    }

    private void loadDeviceConfigConstants() {
    void loadDeviceConfigConstants() {
        mOnDeviceConfigChangedListener.onPropertiesChanged(
                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER));
        mOnDeviceConfigChangedForComponentAliasListener.onPropertiesChanged(
+7 −9
Original line number Diff line number Diff line
@@ -4567,14 +4567,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
        synchronized (mProcLock) {
            app.mState.setCurAdj(ProcessList.INVALID_ADJ);
            app.mState.setSetAdj(ProcessList.INVALID_ADJ);
            app.mState.setVerifiedAdj(ProcessList.INVALID_ADJ);
            mOomAdjuster.setAttachingSchedGroupLSP(app);
            app.mState.setForcingToImportant(null);
            mOomAdjuster.setAttachingProcessStatesLSP(app);
            clearProcessForegroundLocked(app);
            app.mState.setHasShownUi(false);
            app.mState.setCached(false);
            app.setDebugging(false);
            app.setKilledByAm(false);
            app.setKilled(false);
@@ -4741,8 +4735,14 @@ public class ActivityManagerService extends IActivityManager.Stub
                app.makeActive(thread, mProcessStats);
                checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
            }
            app.setPendingFinishAttach(true);
            updateLruProcessLocked(app, false, null);
            checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
            updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN);
            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
            final long now = SystemClock.uptimeMillis();
            synchronized (mAppProfiler.mProfilerLock) {
                app.mProfile.setLastRequestedGc(now);
@@ -4758,8 +4758,6 @@ public class ActivityManagerService extends IActivityManager.Stub
            if (!mConstants.mEnableWaitForFinishAttachApplication) {
                finishAttachApplicationInner(startSeq, callingUid, pid);
            } else {
                app.setPendingFinishAttach(true);
            }
        } catch (Exception e) {
            // We need kill the process group here. (b/148588589)
+4 −7
Original line number Diff line number Diff line
@@ -3689,14 +3689,11 @@ final class ActivityManagerShellCommand extends ShellCommand {
            if (foregroundActivities) {
                try {
                    int prcState = mIam.getUidProcessState(uid, "android");
                    ProcessRecord topApp = mInternal.getTopApp();
                    if (topApp == null) {
                        mPw.println("No top app found");
                    } else {
                        int topPid = topApp.getPid();
                        if (prcState == ProcessStateEnum.TOP && topPid == pid) {

                    if (prcState == ProcessStateEnum.TOP) {
                        mPw.println("New foreground process: " + pid);
                        }
                    } else {
                        mPw.println("No top app found");
                    }
                    mPw.flush();
                } catch (RemoteException e) {
+36 −3
Original line number Diff line number Diff line
@@ -1292,12 +1292,19 @@ public class OomAdjuster {
        for (int i = numLru - 1; i >= 0; i--) {
            ProcessRecord app = lruList.get(i);
            final ProcessStateRecord state = app.mState;
            if (!app.isKilledByAm() && app.getThread() != null && !app.isPendingFinishAttach()) {
            if (!app.isKilledByAm() && app.getThread() != null) {
                // We don't need to apply the update for the process which didn't get computed
                if (state.getCompletedAdjSeq() == mAdjSeq) {
                    applyOomAdjLSP(app, true, now, nowElapsed, oomAdjReason);
                }

                if (app.isPendingFinishAttach()) {
                    // Avoid trimming processes that are still initializing. If they aren't
                    // hosting any components yet because they may be unfairly killed.
                    // We however apply the oom scores set at #setAttachingProcessStatesLSP.
                    continue;
                }

                final ProcessServiceRecord psr = app.mServices;
                // Count the number of process types.
                switch (state.getCurProcState()) {
@@ -2804,6 +2811,18 @@ public class OomAdjuster {
            capability &= ~PROCESS_CAPABILITY_BFSL;
        }


        if (app.isPendingFinishAttach()) {
            // If the app is still starting up. We reset the computations to the
            // hardcoded values in setAttachingProcessStatesLSP. This ensures that the app keeps
            // hard-coded default 'startup' oom scores while starting up. When it finishes startup,
            // we'll recompute oom scores based on it's actual hosted compoenents.
            setAttachingProcessStatesLSP(app);
            state.setAdjSeq(mAdjSeq);
            state.setCompletedAdjSeq(state.getAdjSeq());
            return false;
        }

        // Do final modification to adj.  Everything we do between here and applying
        // the final setAdj must be done in this function, because we will also use
        // it when computing the final cached adj later.  Note that we don't need to
@@ -3242,8 +3261,11 @@ public class OomAdjuster {
    }

    @GuardedBy({"mService", "mProcLock"})
    void setAttachingSchedGroupLSP(ProcessRecord app) {
    void setAttachingProcessStatesLSP(ProcessRecord app) {
        int initialSchedGroup = SCHED_GROUP_DEFAULT;
        int initialProcState = PROCESS_STATE_CACHED_EMPTY;
        int initialCapability =  PROCESS_CAPABILITY_NONE;
        boolean initialCached = true;
        final ProcessStateRecord state = app.mState;
        // If the process has been marked as foreground, it is starting as the top app (with
        // Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
@@ -3255,13 +3277,24 @@ public class OomAdjuster {
                app.getWindowProcessController().onTopProcChanged();
                setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
                initialSchedGroup = SCHED_GROUP_TOP_APP;
                initialProcState = PROCESS_STATE_TOP;
                initialCapability = PROCESS_CAPABILITY_ALL;
                initialCached = false;
            } catch (Exception e) {
                Slog.w(TAG, "Failed to pre-set top priority to " + app + " " + e);
            }
        }

        state.setSetSchedGroup(initialSchedGroup);
        state.setCurrentSchedulingGroup(initialSchedGroup);
        state.setCurProcState(initialProcState);
        state.setCurRawProcState(initialProcState);
        state.setCurCapability(initialCapability);
        state.setCached(initialCached);

        state.setCurAdj(ProcessList.FOREGROUND_APP_ADJ);
        state.setCurRawAdj(ProcessList.FOREGROUND_APP_ADJ);
        state.setForcingToImportant(null);
        state.setHasShownUi(false);
    }

    // ONLY used for unit testing in OomAdjusterTests.java
+8 −4
Original line number Diff line number Diff line
@@ -131,6 +131,7 @@ public class AsyncProcessStartTest {

        mRealAms = new ActivityManagerService(
                new TestInjector(mContext), mServiceThreadRule.getThread());
        mRealAms.mConstants.loadDeviceConfigConstants();
        mRealAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
        mRealAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
        mRealAms.mAtmInternal = mActivityTaskManagerInt;
@@ -195,8 +196,10 @@ public class AsyncProcessStartTest {
            Log.v(TAG, "Intercepting bindApplication() for "
                    + Arrays.toString(invocation.getArguments()));
            if (!wedge) {
                if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
                    mRealAms.finishAttachApplication(0);
                }
            }
            return null;
        }).when(thread).bindApplication(
                any(), any(),
@@ -237,10 +240,11 @@ public class AsyncProcessStartTest {
     */
    @Test
    public void testNormal() throws Exception {
        if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) {
            ProcessRecord app = startProcessAndWait(false);

            verify(app, never()).killLocked(any(), anyInt(), anyBoolean());
        }
    }

    /**
     * Verify that we kill a wedged process after the process start timeout
Loading