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

Commit 8a946927 authored by Mark Fasheh's avatar Mark Fasheh
Browse files

frameworks: Add highly concurrent MessageQueue implementations

Move MessageQueue.java to LegacyMessageQueue.java and add two variants
on an optional implemenation which we can switch on via build flag.
The 'legacy' MessageQueue class stays the default. ConcurrentMessageQueue
and SemiConcurrentMessageQueue keeps the same API from MessageQueue.

We enqueue new messages onto a lockless (treiber) stack. Next()
walks the stack and enqueues items into a priority queue which is
then used to determine the next messages to deliver.
This gives us amortized constant time insertions - next() pays
the price of O(Log n) inserts.

Remove is still a liner time operation as the API around it makes it
impossible to remove items without doing a full scan.

For ConcurrentMessageQueue, remove() runs in parallel to insert and next().

For SemiConcurrentMessageQueue, remove() and next() are mutually excluded.

The difference between ConcurrentMessageQueue and SemiConcurrentMessageQueue
is in priority queue implementations. One uses the lockless
ConcurrentSkipListSet while the other uses PriorityQueue with a lock around
priority queue operations.

We are not sure about the average case performance of ConcurrentSkipListSet,
hence the 'SemiConcurrent' implementation.

Flag: build.RELEASE_PACKAGE_MESSAGEQUEUE_IMPLEMENTATION
Test: atest MessageQueueTest
Test: boot phone and use it
Bug: 336880969
Change-Id: I69108655dfcde6e54c5bb5d00f3b3b47967d814f
parent a8fdd28e
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -20,10 +20,43 @@ filegroup {
        "**/*.java",
        "**/*.aidl",
        ":framework-nfc-non-updatable-sources",
        ":messagequeue-gen",
    ],
    // Exactly one of the below will be added to srcs by messagequeue-gen
    exclude_srcs: [
        "android/os/LegacyMessageQueue/MessageQueue.java",
        "android/os/ConcurrentMessageQueue/MessageQueue.java",
        "android/os/SemiConcurrentMessageQueue/MessageQueue.java",
    ],
    visibility: ["//frameworks/base"],
}

// Add selected MessageQueue.java implementation to srcs
soong_config_module_type {
    name: "release_package_messagequeue_implementation_srcs",
    module_type: "genrule",
    config_namespace: "messagequeue",
    value_variables: ["release_package_messagequeue_implementation"],
    properties: [
        "srcs",
    ],
}

// Output the selected android/os/MessageQueue.java implementation
release_package_messagequeue_implementation_srcs {
    name: "messagequeue-gen",
    soong_config_variables: {
        release_package_messagequeue_implementation: {
            srcs: ["android/os/%s"],
            conditions_default: {
                srcs: ["android/os/LegacyMessageQueue/MessageQueue.java"],
            },
        },
    },
    cmd: "mkdir -p android/os/; cp $(in) $(out);",
    out: ["android/os/MessageQueue.java"],
}

aidl_library {
    name: "IDropBoxManagerService_aidl",
    srcs: [
+1648 −0

File added.

Preview size limit exceeded, changes collapsed.

+15 −4
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Handler;
import android.os.Process;
import android.os.Trace;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -29,6 +32,7 @@ import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Low-level class holding the list of messages to be dispatched by a
@@ -44,6 +48,7 @@ import java.util.ArrayList;
public final class MessageQueue {
    private static final String TAG = "MessageQueue";
    private static final boolean DEBUG = false;
    private static final boolean TRACE = false;

    // True if the message queue can be quit.
    @UnsupportedAppUsage
@@ -326,6 +331,8 @@ public final class MessageQueue {
        return newWatchedEvents;
    }

    private static final AtomicLong mMessagesDelivered = new AtomicLong();

    @UnsupportedAppUsage
    Message next() {
        // Return here if the message loop has already quit and been disposed.
@@ -381,6 +388,9 @@ public final class MessageQueue {
                        if (msg.isAsynchronous()) {
                            mAsyncMessageCount--;
                        }
                        if (TRACE) {
                            Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet());
                        }
                        return msg;
                    }
                } else {
@@ -1093,6 +1103,7 @@ public final class MessageQueue {

    void dump(Printer pw, String prefix, Handler h) {
        synchronized (this) {
            pw.println(prefix + "(MessageQueue is using Legacy implementation)");
            long now = SystemClock.uptimeMillis();
            int n = 0;
            for (Message msg = mMessages; msg != null; msg = msg.next) {
+1589 −0

File added.

Preview size limit exceeded, changes collapsed.