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

Commit 532b14d0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert^2 "Avoid locks in various singleton HandlerThread types"" into main

parents 5536d060 d4df5202
Loading
Loading
Loading
Loading
+36 −28
Original line number Diff line number Diff line
@@ -32,9 +32,13 @@ import java.util.concurrent.Executor;
public final class BackgroundThread extends HandlerThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 10_000;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 30_000;
    private static BackgroundThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;

    // Note: These static fields are shadowed in Robolectric, and cannot be easily changed without
    // breaking downstream tests. This makes refactoring or optimization a bit messier than it could
    // be, e.g., using common lazy singleton abstractions or the holder init pattern.
    private static volatile BackgroundThread sInstance;
    private static volatile Handler sHandler;
    private static volatile HandlerExecutor sHandlerExecutor;

    private BackgroundThread() {
        super("android.bg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -47,17 +51,25 @@ public final class BackgroundThread extends HandlerThread {
        }
    }

    private static void ensureThreadReadyLocked() {
        ensureThreadStartedLocked();
    private static void ensureThreadReady() {
        // Note: Due to the way Robolectric shadows sHandler, we use it as the signal of readiness.
        if (sHandler != null) {
            return;
        }
        synchronized (BackgroundThread.class) {
            if (sHandler == null) {
                ensureThreadStartedLocked();
                // This will block until the looper is initialized on the background thread.
                final Looper looper = sInstance.getLooper();
                looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
                looper.setSlowLogThresholdMs(
                        SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            sHandler = new Handler(sInstance.getLooper(), /*callback=*/ null, /* async=*/ false,
                Handler handler = new Handler(looper, /*callback=*/ null, /* async=*/ false,
                        /* shared=*/ true);
            sHandlerExecutor = new HandlerExecutor(sHandler);
                sHandlerExecutor = new HandlerExecutor(handler);
                // Assigned last to signal full readiness.
                sHandler = handler;
            }
        }
    }

@@ -65,32 +77,28 @@ public final class BackgroundThread extends HandlerThread {
     * Starts the thread if needed, but doesn't block on thread initialization or readiness.
     */
    public static void startIfNeeded() {
        if (sInstance == null) {
            synchronized (BackgroundThread.class) {
                ensureThreadStartedLocked();
            }
        }
    }

    @NonNull
    public static BackgroundThread get() {
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
        ensureThreadReady();
        return sInstance;
    }
    }

    @NonNull
    public static Handler getHandler() {
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
        ensureThreadReady();
        return sHandler;
    }
    }

    @NonNull
    public static Executor getExecutor() {
        synchronized (BackgroundThread.class) {
            ensureThreadReadyLocked();
        ensureThreadReady();
        return sHandlerExecutor;
    }
}
}
+15 −28
Original line number Diff line number Diff line
@@ -38,45 +38,32 @@ public final class FgThread extends ServiceThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;

    private static FgThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;
    private static final class NoPreloadHolder {
        private static final FgThread sInstance = new FgThread();
    }

    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;

    private FgThread() {
        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
    }

    private static void ensureThreadLocked() {
        if (sInstance == null) {
            sInstance = new FgThread();
            sInstance.start();
            final Looper looper = sInstance.getLooper();
        start();
        final Looper looper = getLooper();
        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
            looper.setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            sHandler = makeSharedHandler(sInstance.getLooper());
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
        looper.setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        mHandler = makeSharedHandler(looper);
        mHandlerExecutor = new HandlerExecutor(mHandler);
    }

    public static FgThread get() {
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sInstance;
        }
        return NoPreloadHolder.sInstance;
    }

    public static Handler getHandler() {
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sHandler;
        }
        return NoPreloadHolder.sInstance.mHandler;
    }

    public static Executor getExecutor() {
        synchronized (FgThread.class) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
        return NoPreloadHolder.sInstance.mHandlerExecutor;
    }
}
+15 −25
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;

import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Trace;

import java.util.concurrent.Executor;
@@ -28,42 +29,31 @@ import java.util.concurrent.Executor;
 * (not waiting for data itself, but communicating with network daemons).
 */
public final class IoThread extends ServiceThread {
    private static IoThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;
    private static final class NoPreloadHolder {
        private static final IoThread sInstance = new IoThread();
    }

    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;

    private IoThread() {
        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
    }

    private static void ensureThreadLocked() {
        if (sInstance == null) {
            sInstance = new IoThread();
            sInstance.start();
            sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
            sHandler = makeSharedHandler(sInstance.getLooper());
            sHandlerExecutor = new HandlerExecutor(sHandler);
        }
        start();
        final Looper looper = getLooper();
        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
        mHandler = new Handler(looper, /*callback=*/ null, /* async=*/ false, /* shared=*/ true);
        mHandlerExecutor = new HandlerExecutor(mHandler);
    }

    public static IoThread get() {
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sInstance;
        }
        return NoPreloadHolder.sInstance;
    }

    public static Handler getHandler() {
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sHandler;
        }
        return NoPreloadHolder.sInstance.mHandler;
    }

    public static Executor getExecutor() {
        synchronized (IoThread.class) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
        return NoPreloadHolder.sInstance.mHandlerExecutor;
    }
}
+13 −35
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Trace;

import com.android.internal.annotations.GuardedBy;

import java.util.concurrent.Executor;

/**
@@ -34,61 +32,41 @@ public final class PermissionThread extends ServiceThread {
    private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
    private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;

    private static final Object sLock = new Object();
    private static final class NoPreloadHolder {
        private static final PermissionThread sInstance = new PermissionThread();
    }

    @GuardedBy("sLock")
    private static PermissionThread sInstance;
    private static Handler sHandler;
    private static HandlerExecutor sHandlerExecutor;
    private final Handler mHandler;
    private final HandlerExecutor mHandlerExecutor;

    private PermissionThread() {
        super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
    }

    @GuardedBy("sLock")
    private static void ensureThreadLocked() {
        if (sInstance != null) {
            return;
        }

        sInstance = new PermissionThread();
        sInstance.start();
        final Looper looper = sInstance.getLooper();
        start();
        final Looper looper = getLooper();
        looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
        looper.setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        sHandler = new Handler(sInstance.getLooper());
        sHandlerExecutor = new HandlerExecutor(sHandler);
        looper.setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        mHandler = new Handler(looper);
        mHandlerExecutor = new HandlerExecutor(mHandler);
    }

    /**
     * Obtain a singleton instance of the PermissionThread.
     */
    public static PermissionThread get() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sInstance;
        }
        return NoPreloadHolder.sInstance;
    }

    /**
     * Obtain a singleton instance of a handler executing in the PermissionThread.
     */
    public static Handler getHandler() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandler;
        }
        return NoPreloadHolder.sInstance.mHandler;
    }


    /**
     * Obtain a singleton instance of an executor of the PermissionThread.
     */
    public static Executor getExecutor() {
        synchronized (sLock) {
            ensureThreadLocked();
            return sHandlerExecutor;
        }
        return NoPreloadHolder.sInstance.mHandlerExecutor;
    }
}