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

Commit 3f40ee59 authored by Mark Fasheh's avatar Mark Fasheh
Browse files

Add WaitState class for new MessageQueue

This encapsulates our logic for manipulating an atomic bitfield.

WaitState can be a counter or a deadline.

When it's a counter, the bit WAIT_STATE_IS_COUNTER is set and
the lower 63 bits are used as a long.

When WaitState is a deadline, we reserve bit 62 to indicate a
sync barrier. The middle 42 bits are used for the millisecond
resolution timestamp and the remaining 20 bits are used as a
counter.

Test: atest android.os.WaitStateTest
Bug: 421623328
Flag: EXEMPT new data structure isn't used yet; usages will be flagged.
Change-Id: I9f1a49378ce4c2cfda0f50d4febc57b050e55aef
parent ab70951a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ per-file HandlerThread.java = file:/MESSAGE_QUEUE_OWNERS
per-file HandlerExecutor.java = file:/MESSAGE_QUEUE_OWNERS
per-file MessageHeap.java = file:/MESSAGE_QUEUE_OWNERS
per-file MessageStack.java = file:/MESSAGE_QUEUE_OWNERS
per-file WaitState.java = file:/MESSAGE_QUEUE_OWNERS

# Stats
per-file IStatsBootstrapAtomService.aidl = file:/services/core/java/com/android/server/stats/OWNERS
+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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 athasEqualMessages
 *
 *      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 android.os;

/**
 * Encapsulates the waiting logic of DeliQueue/MessageQueue
 * @hide
 */
public final class WaitState {
    private static final long IS_COUNTER = 1L  << 63;
    private static final long HAS_SYNC_BARRIER = 1L << 62;
    private static final long MASK = ~(IS_COUNTER | HAS_SYNC_BARRIER);

    public static boolean isCounter(long state) {
        return (state & IS_COUNTER) != 0;
    }

    public static long getCount(long state) {
        return state & ~IS_COUNTER;
    }

    public static long incrementCounter(long state) {
        long count = getCount(state) + 1;
        return count | IS_COUNTER;
    }

    public static long initCounter() {
        return IS_COUNTER;
    }

    public static boolean hasSyncBarrier(long state) {
        return (state & HAS_SYNC_BARRIER) != 0;
    }

    private static final long COUNTER_BITS = 20;
    public static long getTSMillis(long state) {
        return (state & MASK) >>> COUNTER_BITS;
    }

    public static long incrementDeadline(long state) {
        long bits = state & ~MASK;
        long ts = state & MASK;
        return (ts + 1) | bits;
    }

    public static long composeDeadline(long deadlineMS, boolean syncBarrier) {
        long state = deadlineMS << COUNTER_BITS;
        if (syncBarrier) {
            state |= HAS_SYNC_BARRIER;
        }

        return state;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ per-file RemoteCallbackListTest.java = shayba@google.com
per-file MessageQueueTest.java = file:/MESSAGE_QUEUE_OWNERS
per-file MessageHeapTest.java = file:/MESSAGE_QUEUE_OWNERS
per-file MessageStackTest.java = file:/MESSAGE_QUEUE_OWNERS
per-file WaitStateTest.java = file:/MESSAGE_QUEUE_OWNERS

# Perfetto SDK
per-file PerfettoTrace*Test.java = file:/PERFETTO_OWNERS
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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 athasEqualMessages
 *
 *      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 android.os;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.os.WaitState;

import android.util.Log;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public final class WaitStateTest {
    private static final String TAG = "WaitStateTest";

    @Test
    public void testCountOperations() {
        long state = WaitState.initCounter();

        assertTrue(WaitState.isCounter(state));
        assertEquals(WaitState.getCount(state), 0);
        Log.d(TAG, "state = " + Long.toHexString(state));

        state = WaitState.incrementCounter(state);
        Log.d(TAG, "state = " + Long.toHexString(state));
        assertTrue(WaitState.isCounter(state));
        assertEquals(WaitState.getCount(state), 1);
        for (int i = 2; i < 10; i++) {
            state = WaitState.incrementCounter(state);
            assertEquals(WaitState.getCount(state), i);
            assertTrue(WaitState.isCounter(state));
        }
    }

    @Test
    public void testDeadlineOperations() {
        final long now = SystemClock.uptimeMillis();
        long state = WaitState.composeDeadline(now, false);
        assertFalse(WaitState.hasSyncBarrier(state));
        long tsMillis = WaitState.getTSMillis(state);
        assertEquals(tsMillis, now);

        state = WaitState.incrementDeadline(state);
        state = WaitState.incrementDeadline(state);
        tsMillis = WaitState.getTSMillis(state);
        assertEquals(tsMillis, now);


        /* Do the same but with sync barrier bit set */
        state = WaitState.composeDeadline(now, true);
        assertTrue(WaitState.hasSyncBarrier(state));
        tsMillis = WaitState.getTSMillis(state);
        assertEquals(tsMillis, now);

        state = WaitState.incrementDeadline(state);
        state = WaitState.incrementDeadline(state);
        tsMillis = WaitState.getTSMillis(state);
        assertEquals(tsMillis, now);
    }
}